﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
using System.Diagnostics;
using Davsha.App.Properties;
using Davsha.App.Actions;

namespace Davsha.App
{
    class MainNotifyIcon
    {
        private ActionInfo _pedalPressAction;
        private ActionInfo _pedalDoublePressAction;
        private NotifyIcon _notifyIcon;
        private ActionInfoCollection _actions;
        private InterceptKeyEventsForm _interceptKeyEventsForm;
        private Pedal _pedal;
        private System.Windows.Forms.Timer _identifyTimer;
        private Stopwatch _identifyTimeoutWatch;

        public MainNotifyIcon()
        {
            _actions = ActionInfoCollection.FromXml(Settings.Default.ActionsFilePath);
            _interceptKeyEventsForm = new InterceptKeyEventsForm();

            _pedal = new Pedal(_interceptKeyEventsForm.Handle, new DeviceInfo(Settings.Default.PedalVendorId, Settings.Default.PedalProductId));
            _pedal.PedalPress += new DevicePressEventHandler(Pedal_PedalPress);
            _pedal.PedalDoublePress += new DevicePressEventHandler(Pedal_PedalDoublePress);
            _pedal.Error += new ErrorEventHandler(Pedal_Error);

            _identifyTimer = new System.Windows.Forms.Timer();
            _identifyTimer.Enabled = false;
            _identifyTimer.Interval = 100;
            _identifyTimer.Tick += new EventHandler(IdentifyTimer_Tick);

            PrepareNotifyIcon();
        }

        public bool Visible
        {
            get
            {
                return _notifyIcon.Visible;
            }
            set
            {
                _notifyIcon.Visible = value;
            }
        }

        private void PrepareNotifyIcon()
        {
            _notifyIcon = new NotifyIcon();

            _notifyIcon.Icon = new Icon("app.ico");
            _notifyIcon.Text = "Davsha";

            _notifyIcon.ContextMenu = new ContextMenu();

            MenuItem identifyMenuItem = new MenuItem();
            identifyMenuItem.Text = "Identify Pedal";
            identifyMenuItem.Click += new EventHandler(IdentifyMenuItem_Click);
            _notifyIcon.ContextMenu.MenuItems.Add(identifyMenuItem);

            _pedalPressAction = AddActionsMenu("Pedal Press Action", ActionTargetEventType.PedalPress, Settings.Default.SelectedPressAction);
            _pedalDoublePressAction = AddActionsMenu("Pedal Double Press Action", ActionTargetEventType.PedalDoublePress, Settings.Default.SelectedDoublePressAction);

            MenuItem exitMenuItem = new MenuItem();
            exitMenuItem.Text = "E&xit";
            exitMenuItem.Click += new EventHandler(Exit_Click);
            _notifyIcon.ContextMenu.MenuItems.Add(exitMenuItem);

            _notifyIcon.Visible = true;
        }

        private ActionInfo AddActionsMenu(string text, ActionTargetEventType targetEventType, string selectedActionName)
        {
            MenuItem menuItemPress = new MenuItem();
            _notifyIcon.ContextMenu.MenuItems.Add(menuItemPress);
            //menuItemPress.Index = 0;
            menuItemPress.Text = text;

            ActionInfo selectedAction = null;

            foreach (ActionInfo action in _actions)
            {
                ActionMenuItem actionMenuItem = new ActionMenuItem(action, targetEventType);
                menuItemPress.MenuItems.Add(actionMenuItem);
                actionMenuItem.Click += new EventHandler(ActionMenuItem_Click);
                actionMenuItem.RadioCheck = true;

                if (selectedAction == null && action.Name.Equals(selectedActionName))
                {
                    actionMenuItem.Checked = true;
                    selectedAction = action;
                }
            }

            return selectedAction;
        }

        private void IdentifyMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                _notifyIcon.ShowBalloonTip(Settings.Default.IdentifyPedalTimeout, "Identify Pedal", "Please press pedal.", ToolTipIcon.Info);
                StartIdentifying();
            }
            catch (Exception x)
            {
                HandleException(x);
            }
        }
        
        private void ActionMenuItem_Click(object sender, EventArgs e)
        {
            ActionMenuItem actionMenuItem = sender as ActionMenuItem;
            
            if (actionMenuItem == null)
            {
                return;
            }

            if (actionMenuItem.TargetEventType == ActionTargetEventType.PedalPress)
            {
                _pedalPressAction = actionMenuItem.Action;
                Settings.Default.SelectedPressAction = actionMenuItem.Action.Name;
                Settings.Default.Save();
            }
            else if (actionMenuItem.TargetEventType == ActionTargetEventType.PedalDoublePress)
            {
                _pedalDoublePressAction = actionMenuItem.Action;
                Settings.Default.SelectedDoublePressAction = actionMenuItem.Action.Name;
                Settings.Default.Save();
            }

            actionMenuItem.Checked = true;

            if (actionMenuItem.Parent != null)
            {
                foreach (MenuItem siblingItem in actionMenuItem.Parent.MenuItems)
                {
                    if (siblingItem != actionMenuItem)
                    {
                        siblingItem.Checked = false;
                    }
                }
            }
        }

        private static void Exit_Click(object Sender, EventArgs e)
        {
            Application.Exit();
        }

        private void Pedal_PedalPress(object sender, DevicePressEventArgs e)
        {
            if (_pedal.IsIdentifying)
            {
                PedalIdentified(e.PedalInfo);
                return;
            }

            ExecuteAction(_pedalPressAction);
        }

        private void Pedal_PedalDoublePress(object sender, DevicePressEventArgs e)
        {
            ExecuteAction(_pedalDoublePressAction);
        }

        private void Pedal_Error(object sender, ErrorEventArgs e)
        {
            HandleException(e.Error);
        }

        private void ExecuteAction(ActionInfo action)
        {
            if (action == null)
            {
                return;
            }

            ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o){
                try
                {
                    Debug.WriteLine("Executing started: " + action.Name);
                    action.Execute();
                    Debug.WriteLine("Executing finished: " + action.Name);
                }
                catch (Exception e)
                {
                    Debug.WriteLine("Executing error: " + action.Name + e);

                    _notifyIcon.ShowBalloonTip(Settings.Default.BaloonMessageTimeout, action.Name + " Error: ", e.Message, ToolTipIcon.Error);
                }
            }));
        }

        private void StartIdentifying()
        {
            _pedal.IsIdentifying = true;
            _identifyTimeoutWatch = Stopwatch.StartNew();
            _identifyTimer.Start();
        }

        private void PedalIdentified(DeviceInfo pedalInfo)
        {
            try
            {
                StopIdentifying();
                _notifyIcon.ShowBalloonTip(Settings.Default.BaloonMessageTimeout, "Pedal Identified Successfully.", "Pedal found.", ToolTipIcon.Info);
                _pedal.PedalInfo = pedalInfo;
                Settings.Default.PedalVendorId = pedalInfo.VendorId;
                Settings.Default.PedalProductId = pedalInfo.ProductId;
                Settings.Default.Save();
            }
            catch (Exception x)
            {
                HandleException(x);
            }
        }

        private void IdentifyTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                if (_identifyTimeoutWatch.ElapsedMilliseconds > Settings.Default.IdentifyPedalTimeout)
                {
                    StopIdentifying();
                }
            }
            catch (Exception x)
            {
                HandleException(x);
            }
        }

        private void StopIdentifying()
        {
            _pedal.IsIdentifying = false;
            _identifyTimeoutWatch.Stop();
            _identifyTimer.Stop();
            _notifyIcon.ShowBalloonTip(Settings.Default.BaloonMessageTimeout, "Identify Pedal Failed", "Pedal not found.", ToolTipIcon.Error);
        }

        private void HandleException(Exception x)
        {
            if (_notifyIcon != null)
            {
                _notifyIcon.ShowBalloonTip(Settings.Default.BaloonMessageTimeout, "Error", x.Message, ToolTipIcon.Error);
            }
        }
    }
}
